package ServerSide.Tests.Threads;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import Mocks.MockGameServer;
import harima.AGameServer.ServerSide.Exceptions.ServerException;
import harima.AGameServer.ServerSide.Threads.WaitForClientsThread;
import junit.framework.TestCase;

public class WaitForClientsThreadFixture extends TestCase {

	WaitForClientsThread thread;

	MockGameServer server = new MockGameServer();

	String serverName = "localhost";

	@Override
	protected void setUp() throws Exception {

		server.port = 99;
		server.running = true;
	}

	@Override
	protected void tearDown() throws Exception {

		thread.stopServerSocket();
	}

	public void test_StartsServerSocket() throws Exception {

		thread = new WaitForClientsThread(server);
		thread.startServerSocket();
		Socket socket = new Socket(serverName, server.port);
	}

	public void test_CanStopServerSocket() throws Exception {
		thread = new WaitForClientsThread(server);
		thread.startServerSocket();
		thread.stopServerSocket();
		boolean connected = false;

		try {
			connected = ((new Socket(serverName, server.port))) != null;
		} catch (Exception e) {

		}

		assertFalse(connected);
	}

	public void test_CannAceptMultipleConnections() throws Exception {
		thread = new WaitForClientsThread(server);

		thread.startServerSocket();

		Socket connection1 = new Socket(serverName, server.port);
		Socket connection2 = new Socket(serverName, server.port);
	}

	public void test_HandlesException_CloseRequested_ServerSocketIsNotOpened()
			throws Exception {
		thread = new WaitForClientsThread(server);
		thread.stopServerSocket();
	}

	public void test_HandlesException_CloseRequested_ServerSocketIsClosed()
			throws Exception {
		thread = new WaitForClientsThread(server);
		thread.startServerSocket();
		thread.stopServerSocket();
		thread.stopServerSocket();
	}

	public void test_ThreadRuns_SeverIsRunning_Always() throws Exception {
		server.running = true;
		thread = new WaitForClientsThread(server);

		Thread runningThread = new Thread(thread);
		runningThread.start();

		Thread.sleep(100);
		assertTrue(runningThread.isAlive());

		server.running = false;
		new Socket(serverName, server.port);
		Thread.sleep(100);
		assertFalse(runningThread.isAlive());
	}

	public void test_AceptsConnections_ThreadRuns_Always() throws Exception {
		thread = new WaitForClientsThread(server);
		new Thread(thread).start();
		int connections = 5;

		for (int i = 0; i < connections; i++) {
			Thread.sleep(100);
			assertNotNull(new Socket(serverName, server.port));
		}
	}

	public void test_ThrowsServerException_CannotStartServerSocket_Always()
			throws Exception {
		ServerSocket temp = occupyServerPort();
		thread = new WaitForClientsThread(server);
		try {
			thread.startServerSocket();
		} catch (Exception e) {
			assertTrue(e instanceof ServerException);
		}
		temp.close();
	}

	public void test_DelegatesExceptionToServer_ServerExceptionArrises_Always()
			throws Exception {
		ServerSocket temp = occupyServerPort();
		thread = new WaitForClientsThread(server);
		thread.run();
		assertEquals(1, server.CCHandleServerException);
		assertNotNull(server.LastExceptionHandled);
		temp.close();
	}

	public void test_AddsClientToServer_ClientConnects_Always()
			throws Exception {
		thread = new WaitForClientsThread(server);
		Thread runningThread = new Thread(thread);
		int connections = 5;
		runningThread.start();
		for(int i=0; i<connections; i++)
		{
			Thread.sleep(100);
			new Socket(serverName, server.port);
			Thread.sleep(100);
			assertEquals(i+1, server.CCAddClient);
			assertNotNull(server.LastClientAdded);
		}
	}

	private ServerSocket occupyServerPort() throws IOException {
		return new ServerSocket(server.port);
	}

}
